/*
 * FreeModbus Libary: BARE Demo Application
 * Copyright (C) 2006 Christian Walter <wolti@sil.at>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * File: $Id$
 */

/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"

/* ----------------------- Defines ------------------------------------------*/
#define REG_INPUT_START 1000
#define REG_INPUT_NREGS 4

/* ----------------------- Static variables ---------------------------------*/
static USHORT   usRegInputStart = REG_INPUT_START;
static USHORT   usRegInputBuf[REG_INPUT_NREGS];

// 十路输入寄存器
#define REG_INPUT_SIZE  10
uint16_t REG_INPUT_BUF[REG_INPUT_SIZE];


// 十路保持寄存器
#define REG_HOLD_SIZE   10
uint16_t REG_HOLD_BUF[REG_HOLD_SIZE];


// 十路线圈
#define REG_COILS_SIZE 10
uint8_t REG_COILS_BUF[REG_COILS_SIZE] = {1, 1, 1, 1, 0, 0, 0, 0, 1, 1};


// 十路离散量
#define REG_DISC_SIZE  10
uint8_t REG_DISC_BUF[REG_DISC_SIZE] = {1,1,1,1,0,0,0,0,1,1};

/* ----------------------- Start implementation -----------------------------*/
// int
// main( void )
// {
//     eMBErrorCode    eStatus;

//     eStatus = eMBInit( MB_RTU, 0x0A, 0, 38400, MB_PAR_EVEN );

//     /* Enable the Modbus Protocol Stack. */
//     eStatus = eMBEnable(  );

//     for( ;; )
//     {
//         ( void )eMBPoll(  );

//         /* Here we simply count the number of poll cycles. */
//         usRegInputBuf[0]++;
//     }
// }

/// CMD4命令处理回调函数
eMBErrorCode
eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
{
    USHORT usRegIndex = usAddress - 1;

    // 非法检测
    if ((usRegIndex + usNRegs) > REG_INPUT_SIZE) {
        return MB_ENOREG;
    }

    // 循环读取
    while (usNRegs > 0) {
        *pucRegBuffer++ = (unsigned char)(REG_INPUT_BUF[usRegIndex] >> 8);
        *pucRegBuffer++ = (unsigned char)(REG_INPUT_BUF[usRegIndex] & 0xFF);
        usRegIndex++;
        usNRegs--;
    }

    // 模拟输入寄存器被改变
    for (usRegIndex = 0; usRegIndex < REG_INPUT_SIZE; usRegIndex++) {
        REG_INPUT_BUF[usRegIndex]++;
    }

    return MB_ENOERR;
}

/// CMD6、3、16命令处理回调函数
eMBErrorCode
eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs,
                 eMBRegisterMode eMode )
{
    USHORT usRegIndex = usAddress - 1;

    // 非法检测
    if ((usRegIndex + usNRegs) > REG_HOLD_SIZE) {
        return MB_ENOREG;
    }

    // 写寄存器
    if (eMode == MB_REG_WRITE) {
        while (usNRegs > 0) {
            REG_HOLD_BUF[usRegIndex] = (pucRegBuffer[0] << 8) | pucRegBuffer[1];
            pucRegBuffer += 2;
            usRegIndex++;
            usNRegs--;
        }
    }

    // 读寄存器
    else {
        while (usNRegs > 0) {
            *pucRegBuffer++ = (unsigned char)(REG_HOLD_BUF[usRegIndex] >> 8);
            *pucRegBuffer++ = (unsigned char)(REG_HOLD_BUF[usRegIndex] & 0xFF);
            usRegIndex++;
            usNRegs--;
        }
    }

    return MB_ENOERR;
}

/// CMD1、5、15命令处理回调函数
eMBErrorCode
eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils,
               eMBRegisterMode eMode )
{
    USHORT usRegIndex = usAddress - 1;
    UCHAR ucBits = 0;
    UCHAR ucState = 0;
    UCHAR ucLoops = 0;

    // 非法检测
    if ((usRegIndex + usNCoils) > REG_COILS_SIZE) {
        return MB_ENOREG;
    }

    if (eMode == MB_REG_WRITE) {
        ucLoops = (usNCoils - 1) / 8 + 1;
        while (ucLoops != 0) {
            ucState = *pucRegBuffer++;
            ucBits = 0;
            while (usNCoils != 0 && ucBits < 8) {
                REG_COILS_BUF[usRegIndex++] = (ucState >> ucBits) & 0X01;
                usNCoils--;
                ucBits++;
            }
            ucLoops--;
        }
    } else {
        ucLoops = (usNCoils - 1) / 8 + 1;
        while (ucLoops != 0) {
            ucState = 0;
            ucBits = 0;
            while (usNCoils != 0 && ucBits < 8) {
                if (REG_COILS_BUF[usRegIndex]) {
                    ucState |= (1 << ucBits);
                }
                usNCoils--;
                usRegIndex++;
                ucBits++;
            }
            *pucRegBuffer++ = ucState;
            ucLoops--;
        }
    }

    return MB_ENOERR;
}

/// CMD2命令处理回调函数
eMBErrorCode
eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{
    USHORT usRegIndex = usAddress - 1;
    UCHAR ucBits = 0;
    UCHAR ucState = 0;
    UCHAR ucLoops = 0;

    // 非法检测
    if ((usRegIndex + usNDiscrete) > REG_DISC_SIZE) {
        return MB_ENOREG;
    }

    ucLoops = (usNDiscrete - 1) / 8 + 1;
    while (ucLoops != 0) {
        ucState = 0;
        ucBits = 0;
        while (usNDiscrete != 0 && ucBits < 8) {
            if (REG_DISC_BUF[usRegIndex]) {
                ucState |= (1 << ucBits);
            }
            usNDiscrete--;
            usRegIndex++;
            ucBits++;
        }
        *pucRegBuffer++ = ucState;
        ucLoops--;
    }

    // 模拟离散量输入被改变
    for (usRegIndex = 0; usRegIndex < REG_DISC_SIZE; usRegIndex++) {
        REG_DISC_BUF[usRegIndex] = !REG_DISC_BUF[usRegIndex];
    }

    return MB_ENOERR;
}
